home *** CD-ROM | disk | FTP | other *** search
/ Your Choice 3 / Your Choice Software Collection 3.iso / prgmming / swag05 / pointers.swg < prev    next >
Text File  |  1994-09-22  |  16KB  |  1 lines

  1. SWAGOLX.EXE (c) 1993 GDSOFT  ALL RIGHTS RESERVED 00002                                                                           1      05-25-9408:21ALL                      ALEXANDER STAUBO         Buffer Streams           SWAG9405            45     ╙═   π{πJB> AS>Use buffered streams.  That way you can access fairly many records onπJB> AS>disk without noticable speed degradation.πJB>                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^πJB> Do you mean from RAM?? Whoah! How do you go about using bufferedπJB> streams?ππActually, you should write a local "cache" for your records.  Ie.,πyour implement an array of records, say 1..50, or, 1..MaxCacheSize,πwhere MaxCacheSize is a defined constant.  Then you have a couple ofπgeneralized procedures for putting/getting records; now, the point is,πwhenever the program asks for a record -that is in the cache-, thatπrecord is read directly from RAM.  If the record is -not- in theπcache, the record is read, and, if there is space in the cache, theπrecord is inserted into the cache.ππLet's try a Pascal implementation.π}ππ        constπ          MaxCacheSize = 50; (* cache can hold 50 records *)ππ        typeπ          (* this is the cache item *)π          PCacheItem = ^TCacheItem;π          TCacheItem =π            recordπ              Offset : Longint; (* file offset of cache record *)π              Rec    : TRecord; (* use your own record type here *)π            end;ππ        varπ          Cache : array[1..MaxCacheSize] of PCacheItem;π          CacheSize : Word;ππ        procedure InitCache;π          {-Resets cache}π        beginπ          CacheSize:=0;π        end;ππ        function FindCache (Offset : Longint) : PCacheItem;π          {-Returns cache item for Offset if found, otherwise nil}π        varπ          W : Word;π        beginπ          for W:=1 to CacheSize doπ            if Cache[W]^.Offset = Offset thenπ              beginπ                FindCache:=Cache[W];π                Exit;π              end;π          FindCache:=nil;π        end;ππ        varπ          F : file of TRecord; (* file in question *)ππ        procedure PutRecord (Offset : Longint; var Rec : TRecord);π          {-Put record into cache and file}π        varπ          P : PCacheItem;π        beginπ          Write(F, Rec);ππ          (* if exists in RAM (cache), update it *)π          P:=FindCache(Offset);π          if P <> nil thenπ            P^.Rec:=Recπ          elseπ            beginπ              (* put into cache *)π              Inc(CacheSize);π              New(Cache[CacheSize]);π              Cache[CacheSize]^.Offset:=Offset;π              Cache[CacheSize]^.Rec:=Rec;π            end;π        end;ππ        procedure GetRecord (Offset : Longint; var Rec : TRecord);π          {-Get record from cached file}π        varπ          P : PCacheItem;π        beginπ          (* if exists in RAM (cache), get it *)π          P:=FindCache(Offset);π          if P <> nil thenπ            Rec:=P^.Recπ          else if CacheSize < MaxCacheSize thenπ            beginπ              (* read record from file *)π              Read(F, Rec);ππ              (* put into cache *)π              Inc(CacheSize);π              New(Cache[CacheSize]);π              Cache[CacheSize]^.Offset:=Offset;π              Cache[CacheSize]^.Rec:=Rec;π            end;π        end;ππTo use the routines:ππ          Assign(F, 'MYFILE.DAT');π          Reset(F);π          GetRecord(FilePos(F), MyRec);π          GetRecord(FilePos(F), MyRec);π          GetRecord(FilePos(F), MyRec);π          PutRecord(FilePos(F), MyRec);π          Close(F);ππOr something like that, anyway.ππNow, there is a simpler way; "simpler" in this case means "some guyπhas already spent hours writing it just for you".  The concept isπcalled streams.  Now, I don't know how "novice" a programmer you are,πbut knowledge of streams requires knowledge of OOP.  I suggest youπread about OOP right away.ππStreams work in a very simple way.  You have a basic, "abstract"πobject, which provides some simple I/O tools.  A stream is a type ofπ(abstract) file, an input/output mechanism, that you may manipulate;πmost often it's on a hierarchical level, ie., the high-levelπprocedures call low-level procedures, just like DOS.  Think of streamsπas the Pascal type "file", except now the stream is a shell forπanything.ππThe shell implements a -standard- interface for any kind ofπinformation area.  You have file streams, buffered streams (streamsπthat caches areas of the file in memory to optimize accessπefficiency), EMS streams (yes, you can have a "virtual file" that liesπin EMS memory and may be used just like a file), and so on.  Theπstandardization implies that you may write more flexible programs.ππA tiny example:ππ        varπ          S   : TBufStream;π          T   : TRecord;π          Str : string;π        beginπ          S.Init('MYFILE.DAT', stOpen, 2048);π              (* |             |          |π                 file name     file mode  buffer sizeπ              *)π          S.Read(T, SizeOf(T));π          S.Write(T, SizeOf(T));π          Str:=S.ReadStr^;ππ          S.Done;π        end;ππThe corresponding boring-old-Dos example'd be:ππ        varπ          F   : file;π          T   : TRecord;π          Str : string;π        beginπ          (* note: no buffering -> slower! *)π          Assign(F, 'MYFILE.DAT');π          Reset(F, 1);ππ          BlockRead(F, T, SizeOf(T));π          BlockWrite(F, T, SizeOf(T));π          Read(F, Str[0]);π          BlockRead(F, Str[1], Ord(Str[0]));ππ          Close(F);π        end;ππIn the end, streams -are- simpler, too.  And they are extremely fast;πa friend of mine is writing a mail reader and is using object streamsπfor the message/conference/etc. databases.  Now, personally I useπindexed, light-speed B-tree databases.  And his work -just fine-.π                                                                  2      05-26-9411:06ALL                      BILL ZECH                Linked List Routine      SWAG9405            82     ╙═   π{ Links Unit - Turbo Pascal 5.5π  Patterned after the list processing facility in Simula class SIMSET.π  Simula fans will note the same naming conventions as Simula-67.ππ  Written by Bill Zech @CIS:[73547,1034]), May 16, 1989.ππ  The Links unit defines objects and methods useful for implementingπ  list (set) membership in your own objects.ππ  Any object which inherits object <Link> will acquire the attributesπ  needed to maintain that object in a doubly-linked list.  Because theπ  Linkage object only has one set of forward and backward pointers, aπ  given object may belong to only one list at any given moment.  Thisπ  is sufficient for many purposes.  For example, a task control blockπ  might belong in either a ready list, a suspended list, or a swappedπ  list, but all are mutually exclusive.ππ  A list is defined as a head node and zero or more objects linkedπ  to the head node.  A head node with no other members is an emptyπ  list.  Procedures and functions are provided to add members to theπ  end of the list, insert new members in position relative to anπ  existing member, determine the first member, last member, sizeπ  (cardinality) of the list, and to remove members from the list.ππ  Because your object inherits all these attributes, your programπ  need not concern itself with allocating or maintaining pointersπ  or other stuff.  All the actual linkage mechanisms will beπ  transparent to your object.ππ  *Note*π          The following discussion assumes you have defined your objectsπ          as static variables instead of pointers to objects.  For mostπ          programs, dynamic objects manipulated with pointers will beπ          more useful.  Some methods require pointers as arguments.π          Example program TLIST.PAS uses pointer type variables.ππ  Define your object as required, inheriting object Link:ππ                typeπ                        myObjType = object(Link)π                                xxx.....xxxxπ                        end;ππ  To establish a new list, declare a variable for the head nodeπ  as a type Head:ππ                varπ                        Queue1        :Head;π                        Queue2        :Head;ππ        Define your object variables:ππ                varπ                        X    : myObjType;π                        Y    : myObjType;π                        Z    : myObjType;π                        P    :^myObjType;ππ        Make sure the objects have been Init'ed as required for dataπ        initialization, VMT setup, etc.ππ                        Queue1.Init;π                        Queue2.Init;π                        X.Init;π                        Y.Init;π                        Z.Init;ππ        You can add your objects to a list with <Into>:π        (Note the use of the @ operator to make QueueX a pointer to theπ         object.)ππ                beginπ                        X.Into(@Queue1);π                        Y.Into(@Queue2);ππ        You can insert at a specific place with <Precede> or <Follow>:ππ                        Z.Precede(@Y);π                        Z.Follow(@Y);ππ        Remove an object with <Out>:ππ                        Y.Out;ππ        Then add it to another list:ππ                        Y.Into(@Queue1);ππ        Note that <Into>, <Precede> and <Follow> all have a built-inπ        call to Out, so to move an object from one list to another canπ        be had with a single operation:ππ                        Z.Into(@Queue1);ππ        You can determine the first and last elements with <First> and <Last>:π        (Note the functions return pointers to objects.)ππ                        P := Queue1.First;π                        P := Queue1.Last;ππ        The succcessor or predecessor of a given member can be found withπ        fucntions <Suc> and <Pred>:ππ                        P := X.Pred;π                        P := Y.Suc;π                        P := P^.Suc;ππ        The number of elements in a list is found with <Cardinal>:ππ                        N := Queue1.Cardinal;ππ        <Empty> returns TRUE is the list has no members:ππ                        if Queue1.Empty then ...ππ        You can remove all members from a list with <Clear>:ππ                        Queue1.Clear;ππ        GENERAL NOTES:ππ                The TP 5.5 type compatibility rules allow a pointer to aπ                descendant be assigned to an ancestor pointer, but not vice-versa.π                So although it is perfectly legal to assign a pointer toπ                type myObjType to a pointer to type Linkage, it won't letπ                us do it the opposite.ππ                We would like to be able to assign returned values fromπ                Suc, Pred, First, and Last to pointers of type myObjType,π                and the least fussy way is to define these pointer typesπ                internal to this unit as untyped pointers.  This works fineπ                because all we are really doing is passing around pointersπ                to Self, anyway.  The only down-side to this I have noticedπ                is you can't do:  P^.Suc^.Pred because the returned pointerπ                type cannot be dereferenced without a type cast.π}ππunit Links;ππinterfaceππtypeππ  pLinkage = ^Linkage;π  pLink = ^Link;π  pHead = ^Head;ππ  Linkage = objectπ          prede :pLinkage;π          succ  :pLinkage;π          function Suc  :pointer;π          function Pred :pointer;π          constructor Init;π  end;ππ  Link = object(Linkage)π          procedure Out;π          procedure Into(s :pHead);π          procedure Follow (x :pLinkage);π          procedure Precede(x :pLinkage);π  end;ππ  Head = object(Linkage)π          function First :pointer;π          function Last  :pointer;π          function Empty :boolean;π          function Cardinal :integer;π          procedure Clear;π          constructor Init;π  end;ππππimplementationππconstructor Linkage.Init;πbeginπ  succ := NIL;π  prede := NIL;πend;ππfunction Linkage.Suc :pointer;πbeginπ  if TypeOf(succ^) = TypeOf(Head) thenπ         Suc := NILπ  else Suc := succ;πend;ππfunction Linkage.Pred :pointer;πbeginπ  if TypeOf(prede^) = TypeOf(Head) thenπ         Pred := NILπ  else Pred := prede;πend;ππprocedure Link.Out;πbeginπ        if succ <> NIL thenπ        beginπ          succ^.prede := prede;π          prede^.succ := succ;π          succ := NIL;π          prede := NIL;π        end;πend;ππprocedure Link.Follow(x :pLinkage);πbeginπ        Out;π        if x <> NIL thenπ        beginπ          if x^.succ <> NIL thenπ          beginπ                  prede := x;π                  succ := x^.succ;π                  x^.succ := @Self;π                  succ^.prede := @Self;π          end;π        end;πend;πππprocedure Link.Precede(x :pLinkage);πbeginπ        Out;π        if x <> NIL thenπ        beginπ                if x^.succ <> NIL thenπ                beginπ                        succ := x;π                        prede := x^.prede;π                        x^.prede := @Self;π                        prede^.succ := @Self;π                end;π        end;πend;ππprocedure Link.Into(s :pHead);πbeginπ        Out;π        if s <> NIL thenπ        beginπ                succ := s;π                prede := s^.prede;π                s^.prede := @Self;π                prede^.succ := @Self;π        end;πend;πππfunction Head.First :pointer;πbeginπ        First := suc;πend;ππfunction Head.Last :pointer;πbeginπ        Last := Pred;πend;ππfunction Head.Empty :boolean;πbeginπ  Empty := succ = prede;πend;ππfunction Head.Cardinal :integer;πvarπ        i   :integer;π        p   :pLinkage;πbeginπ        i := 0;π        p := succ;π        while p <> @Self doπ          beginπ                  i := i + 1;π                  p := p^.succ;π          end;π        Cardinal := i;πend;ππprocedure Head.Clear;πvarπ        x  : pLink;πbeginπ        x := First;π        while x <> NIL doπ          beginπ                  x^.Out;π                  x := First;π          end;πend;ππconstructor Head.Init;πbeginπ  succ := @Self;π  prede := @Self;πend;ππend.ππ{------------------------   DEMO PROGRAM --------------------- }ππprogram tlist;ππuses Links;ππtypeπ        NameType = string[10];π        person = object(link)π                name :NameType;π                constructor init(nameArg :NameType);π        end;π        Pperson = ^person;ππconstructor person.init(nameArg :NameType);πbeginπ        name := nameArg;π        link.init;πend;ππvarπ        queue : Phead;π        man   : Pperson;π        man2  : Pperson;π        n     : integer;π        tf    : boolean;ππbeginπ        new(queue,Init);π        tf := queue^.Empty;π        new(man,Init('Bill'));π        man^.Into(queue);π        new(man,Init('Tom'));π        man^.Into(queue);π        new(man,Init('Jerry'));π        man^.Into(queue);ππ        man := queue^.First;π        writeln('First man in queue is ',man^.name);π        man := queue^.Last;π        writeln('Last man in queue is ',man^.name);ππ        n := queue^.Cardinal;π        writeln('Length of queue is ',n);π        if not queue^.Empty then writeln('EMPTY reports queue NOT empty');ππ        new(man2,Init('Hugo'));π        man2^.Precede(man);ππ        new(man2,Init('Alfonso'));π        man2^.Follow(man);π        { should now be: Bill Tom Hugo Jerry Alfonso }π        writeln('After PRECEDE and FOLLOW calls, list should be:');π        writeln('  {Bill, Tom, Hugo, Jerry, Alfonso}');π        writeln('Actual list is:');ππ        man := queue^.First;π        while man <> NIL doπ          beginπ                  write(man^.name,' ');π                  man := man^.Suc;π          end;π          writeln;ππ        man := queue^.Last;π        writeln('The same list backwards is:');π        while man <> NIL doπ          beginπ                 write(man^.name,' ');π                 man := man^.Pred;π          end;π          writeln;ππ        n := queue^.Cardinal;π        writeln('Queue size should be 5 now, is: ', n);ππ        queue^.Clear;π        writeln('After clear operation,');π        n := queue^.Cardinal;π        writeln('   Queue size is ',n);π        tf := queue^.Empty;π        if tf then writeln('    and EMTPY reports queue is empty.');π        writeln;π        writeln('Done with test.');πend.ππ